/**
 * 坐骑训练属性校验脚本
 * 目标：验证 4420 训练导致升级后，坐骑属性按“初始值 → 当前转职最大值”的线性公式计算
 * 公式：floor(initial + (max - initial) * (level / maxLevel))
 * 速度字段存储在 currentMp；精字段存储在 currentSp
 */

const http = require('http');
const https = require('https');
const WebSocket = require('ws');

// 可覆盖为你的服务器
const CONFIG = {
    server: { host: process.env.WS_HOST || 'cd521.xin', wsPort: +(process.env.WS_PORT || 8206), httpPort: +(process.env.HTTP_PORT || 80), ssl: !!process.env.WS_SSL },
    user: { mobile: process.env.TEST_MOBILE || '17091271111', pwdSha256: process.env.TEST_PWD_HASH || 'e10adc3949ba59abbe56e057f20f883e' },
};

// 基于实现使用的同一配置（与 src/data/mount-attribute-config.ts 对齐的子集）
const PROMOTION_MAX_LEVELS = { notPromoted: 100, firstPromotion: 120, secondPromotion: 140, thirdPromotion: 160 };
const CONFIG_BY_NAME = {
    '战马': { ap: { initial: 2750, maxLevels: { notPromoted: 2750, firstPromotion: 4142, secondPromotion: 5930, thirdPromotion: 8162 } }, speed: { initial: 50, maxLevels: { notPromoted: 50, firstPromotion: 77, secondPromotion: 108, thirdPromotion: 143 } } },
    '乌云踏雪': { hp: { initial: 13550, maxLevels: { notPromoted: 13550, firstPromotion: 20510, secondPromotion: 29450, thirdPromotion: 40610 } }, ap: { initial: 3500, maxLevels: { notPromoted: 3500, firstPromotion: 5116, secondPromotion: 7156, thirdPromotion: 9668 } } },
    '绝影': { hp: { initial: 13550, maxLevels: { notPromoted: 13550, firstPromotion: 20510, secondPromotion: 29450, thirdPromotion: 40610 } }, sp: { initial: 13550, maxLevels: { notPromoted: 13550, firstPromotion: 20510, secondPromotion: 29450, thirdPromotion: 40610 } } },
    '里飞沙': { ap: { initial: 3500, maxLevels: { notPromoted: 3500, firstPromotion: 5116, secondPromotion: 7156, thirdPromotion: 9668 } }, speed: { initial: 100, maxLevels: { notPromoted: 100, firstPromotion: 132, secondPromotion: 168, thirdPromotion: 208 } } },
    '夜照玉狮子': { hp: { initial: 13550, maxLevels: { notPromoted: 13550, firstPromotion: 20510, secondPromotion: 29450, thirdPromotion: 40610 } }, speed: { initial: 100, maxLevels: { notPromoted: 100, firstPromotion: 132, secondPromotion: 168, thirdPromotion: 208 } } },
    '的卢': { hp: { initial: 17100, maxLevels: { notPromoted: 17100, firstPromotion: 25180, secondPromotion: 35380, thirdPromotion: 47940 } } },
    '爪黄飞电': { sp: { initial: 17100, maxLevels: { notPromoted: 17100, firstPromotion: 25180, secondPromotion: 35380, thirdPromotion: 47940 } } },
    '燎原火': { ap: { initial: 5000, maxLevels: { notPromoted: 5000, firstPromotion: 7064, secondPromotion: 9608, thirdPromotion: 12680 } } },
    '赤兔胭脂兽': { speed: { initial: 150, maxLevels: { notPromoted: 150, firstPromotion: 187, secondPromotion: 228, thirdPromotion: 273 } } },
};

// 可选：从输出基础表中读取初始值（如果存在优先使用）
let baseByName = {};
try {
    const base = require('./output/坐骑基础数据.json');
    baseByName = Object.values(base).reduce((acc, row) => {
        acc[row.name] = row; return acc;
    }, {});
} catch { }

function calcExpected(name, level, transLevel, attrKey) {
    const conf = CONFIG_BY_NAME[name];
    if (!conf) return null;
    let cfg, initial = 0, max = 0;
    let maxLevel = PROMOTION_MAX_LEVELS.notPromoted;
    if (transLevel === 1) maxLevel = PROMOTION_MAX_LEVELS.firstPromotion;
    else if (transLevel === 2) maxLevel = PROMOTION_MAX_LEVELS.secondPromotion;
    else if (transLevel === 3) maxLevel = PROMOTION_MAX_LEVELS.thirdPromotion;

    if (attrKey === 'currentAp') cfg = conf.ap;
    else if (attrKey === 'currentHp') cfg = conf.hp;
    else if (attrKey === 'currentSp') cfg = conf.sp; // 精力
    else if (attrKey === 'currentMp') cfg = conf.speed; // 速度
    if (!cfg) return null;

    // 优先使用基础表初始值
    const base = baseByName[name] || {};
    if (attrKey === 'currentAp' && typeof base.apIni === 'number') initial = base.apIni; else if (attrKey === 'currentHp' && typeof base.hpIni === 'number') initial = base.hpIni; else if (attrKey === 'currentSp' && typeof base.spIni === 'number') initial = base.spIni; else if (attrKey === 'currentMp' && typeof base.mpIni === 'number') initial = base.mpIni; else initial = cfg.initial;

    const maxLevels = cfg.maxLevels || {};
    if (maxLevel === 100) max = maxLevels.notPromoted; else if (maxLevel === 120) max = maxLevels.firstPromotion; else if (maxLevel === 140) max = maxLevels.secondPromotion; else max = maxLevels.thirdPromotion;

    const val = Math.floor(initial + (max - initial) * (Math.floor(level) / maxLevel));
    return val;
}

class Tester {
    constructor() { this.ws = null; this.token = null; this.characters = []; this.characterMounts = []; }

    async run() {
        await this.registerOrIgnore();
        await this.login();
        await this.wsConnect();
        await this.queryCharacters();
        await this.ensureCharacterAndSelect();
        await this.getCharacterMounts();
        if (!this.characterMounts.length) { await this.purchaseDefaultMount('战马', 1); await this.getCharacterMounts(); }
        await this.validateOneCycle();
        await this.close();
    }

    async registerOrIgnore() {
        try {
            const res = await this.http('/user-service/user/register', 'POST', { mobile: CONFIG.user.mobile, pwd: CONFIG.user.pwdSha256, captcha: '123456' });
            if (res && res.code === 0) console.log('📝 注册成功');
        } catch (e) { console.log('👤 注册跳过或已存在'); }
    }

    async login() {
        const res = await this.http('/user-service/user/login', 'POST', { mobile: CONFIG.user.mobile, pwd: CONFIG.user.pwdSha256 });
        if (res.code !== 0) throw new Error('登录失败');
        this.token = res.data.accessToken;
    }

    async wsConnect() {
        await new Promise((resolve, reject) => {
            const proto = CONFIG.server.ssl ? 'wss' : 'ws';
            const url = `${proto}://${CONFIG.server.host}:${CONFIG.server.wsPort}/user-service/websocket?t=${this.token}`;
            this.ws = new WebSocket(url);
            this.ws.on('open', resolve);
            this.ws.on('error', reject);
            setTimeout(() => reject(new Error('WS超时')), 10000);
        });
    }

    async queryCharacters() {
        const msg = await this.sendWait(m => m.act_id === 3, { c: 3, d: null });
        this.characters = msg.roleList || [];
    }

    async ensureCharacterAndSelect() {
        if (!this.characters.length) {
            const name = `测试角色_${Date.now().toString().slice(-6)}`;
            // 兼容创建
            await this.sendWait(m => m.act_id === 5 || m.act_id === 390, { c: 5, d: { name, sex: 1, roleType: 1, headIndex: 2 } });
            await this.delay(800);
            await this.queryCharacters();
        }
        if (!this.characters.length) throw new Error('仍无可选角色');
        await this.sendWait(m => m.act_id === 4, { c: 4, d: { characterId: this.characters[0].id } });
    }

    async getCharacterMounts() {
        const res = await this.sendWait(m => m.act_id === 4424, { c: 4424 });
        this.characterMounts = res.data || [];
        if (!this.characterMounts.length) throw new Error('没有角色坐骑');
    }

    async purchaseDefaultMount(name, baseId) {
        console.log(`尝试购买坐骑: ${name} (基础ID=${baseId})`);
        try {
            await this.sendWait(m => m.act_id === 4424, { c: 4424, d: { id: baseId } });
            await this.delay(500);
        } catch (e) { console.log('购买坐骑失败或已拥有，继续'); }
    }

    // 选择可校验的坐骑（优先里飞沙，否则选任意一个有配置的）
    pickTargetMount() {
        let target = this.characterMounts.find(m => m.name === '里飞沙');
        if (!target) target = this.characterMounts.find(m => CONFIG_BY_NAME[m.name]);
        if (!target) throw new Error('无可校验的坐骑');
        return target;
    }

    async validateOneCycle() {
        let m = this.pickTargetMount();
        console.log(`校验坐骑: ${m.name}, 等级=${m.level}, 转职=${m.transLevel}`);

        // 选择一个可校验的属性键
        const attrKeys = ['currentAp', 'currentHp', 'currentSp', 'currentMp'];
        const key = attrKeys.find(k => typeof m[k] === 'number');
        if (!key) throw new Error('坐骑缺少可校验属性');

        const beforeExpVal = calcExpected(m.name, m.level, m.transLevel, key);
        if (beforeExpVal != null) {
            console.log(`期望(${key})=${beforeExpVal}, 实际=${m[key]}`);
            if (beforeExpVal !== m[key]) {
                console.warn(`⚠️ 初始校验不一致: ${m.name} ${key}: 期望${beforeExpVal} 实际${m[key]}`);
            }
        }

        // 训练一次，等待升级或属性变化
        await this.sendWait(x => x.act_id === 4420, { c: 4420, d: { id: m.id, t: '1' } });
        await this.delay(800);
        const after = await this.sendWait(x => x.act_id === 4424, { c: 4424 });
        const mm = (after.data || []).find(x => x.id === m.id) || m;

        const expectedAfter = calcExpected(mm.name, mm.level, mm.transLevel, key);
        console.log(`升级后等级=${mm.level}, 校验 ${key}: 期望=${expectedAfter}, 实际=${mm[key]}`);

        if (expectedAfter != null && expectedAfter !== mm[key]) {
            throw new Error(`属性校验失败: ${mm.name} ${key}: 期望${expectedAfter} 实际${mm[key]}`);
        }

        console.log('✅ 坐骑训练属性校验通过');
    }

    async close() {
        try { this.ws && this.ws.close(); } catch { }
    }

    // 工具
    async http(path, method, body) {
        return new Promise((resolve, reject) => {
            const useHttps = Number(CONFIG.server.httpPort) === 443 || !!CONFIG.server.ssl;
            const mod = useHttps ? https : http;
            const req = mod.request({ hostname: CONFIG.server.host, port: CONFIG.server.httpPort, path, method, headers: { 'Content-Type': 'application/json' } }, res => {
                let data = ''; res.on('data', c => data += c); res.on('end', () => { try { resolve(JSON.parse(data)); } catch { resolve({}); } });
            });
            req.on('error', reject); if (body) req.write(JSON.stringify(body)); req.end();
        });
    }

    sendWait(filter, payload) {
        return new Promise((resolve, reject) => {
            let timer;
            const handler = m => {
                try { const msg = JSON.parse(m.toString()); if (filter(msg)) { clearTimeout(timer); this.ws.removeListener('message', handler); resolve(msg); } } catch { }
            };
            this.ws.on('message', handler);
            this.ws.send(JSON.stringify(payload));
            timer = setTimeout(() => { this.ws.removeListener('message', handler); reject(new Error('超时')); }, 10000);
        });
    }

    delay(ms) { return new Promise(r => setTimeout(r, ms)); }
}

if (require.main === module) {
    (async () => { try { await new Tester().run(); } catch (e) { console.error('❌ 校验失败:', e.message); process.exit(1); } })();
}


